/*
 * @Descripttion: 
 * @version: 
 * @Author: 
 * @Date: 2021-09-03 11:19:44
 * @LastEditors: xiaochengang
 * @LastEditTime: 2021-09-07 09:22:52
 */
const PENDING = 'pending', FULFILLED = "fulfilled", REJECTED = 'rejected'
class BasePromise {
    constructor(excutor) {
        this.state = PENDING
        this.value = null
        this.reason = null
        this.onResolveCallbacks = []
        this.onRejectCallbacks = []
        try {
            excutor(this.onResolve.bind(this), this.onReject.bind(this))
        } catch (error) {
            this.onReject(error)
        }
    }
    onResolve (value) {
        if (this.state == PENDING) {
            this.state = FULFILLED
            this.value = value
            this.onResolveCallbacks.forEach(cb => cb())
        }
    }
    onReject (reason) {
        if (this.state == PENDING) {
            this.state = REJECTED
            this.reason = reason
            this.onRejectCallbacks.forEach(cb => cb())
        }
    }
    resolvePromise (promise2, value, resolve, reject) {
        if (promise2 == value) {
            throw new Error("Chaining cycle detected for promise #<Promise>")
        }
        if (value instanceof BasePromise) {
            value.then(res => {
                resolve(res)
            }, reason => {
                reject(reason)
            })
        }
        else {
            resolve(value)
        }
    }
    then (onFilfulled, onRejected) {
        onFilfulled = typeof onFilfulled == "function" ? onFilfulled : value => value
        onRejected = typeof onRejected == "function" ? onRejected : err => { throw new Error(err) }
        let promise = new BasePromise((resolve, reject) => {
            if (this.state == PENDING) {
                this.onResolveCallbacks.push(() => {
                    try {
                        let value = onFilfulled(this.value)
                        resolvePromise(promise, value, resolve, reject)


                    } catch (error) {
                        reject(error)
                    }

                })
                this.onRejectCallbacks.push(() => {

                    try {
                        let value = onRejected(this.reason)
                        resolvePromise(promise, value, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                })
            }
            else if (this.state == FULFILLED) {
                setTimeout(() => {
                    try {
                        let value = onFilfulled(this.value)
                        resolvePromise(promise, value, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                })
            }
            else if (this.state == REJECTED) {
                setTimeout(() => {
                    try {
                        let value = onRejected(this.reason)
                        resolvePromise(promise, value, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                })
            }

        })
        return promise
    }
    catch (onRejected) {
        if (this.state == "rejected") {
            onRejected(this.reason)
            // resolvePromise(null, value, resolve, reject)

        }
        else if (this.state == "pending") {
            this.onRejectCallbacks.push(() => {
                onRejected(this.reason)
                // resolvePromise(null, value, resolve, reject)
            })
        }
    }
    static resolve (value) {
        return new BasePromise(resolve => resolve(value))
    }
    static reject (value) {
        return new BasePromise((resolve, reject) => reject(value))
    }
}

export default BasePromise